#include <sys/system.h>
#include <gal/ptgui.h>
#include <gal/surface.h>
#include <SDL/SDL.h>

ptgui_surface_t screen;

ptgui_surface_t * ptgui_surface_get_video_surface(void)
{
	screen.backend = SDL_GetVideoSurface();

	return &screen;
}

void ptgui_surface_update_rects(ptgui_surface_t *surface, pt_uint32_t numrects, ptgui_rect_t *rects)
{
	pt_uint32_t i;
	SDL_Rect *sdl_rects = (SDL_Rect *)pt_malloc(sizeof(SDL_Rect) * numrects);

	for (i = 0; i < numrects; i++) {
		sdl_rects[i].x = rects[i].x1;
		sdl_rects[i].y = rects[i].y1;
		sdl_rects[i].w = ptgui_rect_width(rects[i]);
		sdl_rects[i].h = ptgui_rect_height(rects[i]);
	}
	SDL_UpdateRects(surface->backend, numrects, sdl_rects);

	pt_free(sdl_rects);
}

void ptgui_surface_update_rect(ptgui_surface_t *surface, pt_int32_t x, pt_int32_t y, pt_uint32_t w, pt_uint32_t h)
{
	SDL_UpdateRect(surface->backend, x, y, w, h);
}

pt_int32_t ptgui_surface_flip(ptgui_surface_t *surface)
{
	return SDL_Flip(surface->backend);
}

pt_uint32_t ptgui_surface_map_color
			(ptgui_surface_t *surface, pt_uint8_t r, pt_uint8_t g, pt_uint8_t b)
{
	return SDL_MapRGB(((SDL_Surface*)(surface->backend))->format, r, g, b);
}

void ptgui_surface_unmap_color(pt_uint32_t pixel,
                         ptgui_surface_t *surface, pt_uint8_t *r, pt_uint8_t *g, pt_uint8_t *b)
{
	SDL_GetRGB(pixel, ((SDL_Surface*)(surface->backend))->format, r, g, b);
}

ptgui_surface_t *ptgui_surface_create
			(pt_uint32_t flags, pt_int32_t width, pt_int32_t height, pt_int32_t depth, 
			pt_uint32_t Rmask, pt_uint32_t Gmask, pt_uint32_t Bmask, pt_uint32_t Amask)
{
	ptgui_surface_t *surface;

	surface = (ptgui_surface_t *)pt_malloc(sizeof(ptgui_surface_t));
	surface->backend = SDL_CreateRGBSurface(flags, width, height, depth, Rmask, Gmask, Bmask, Amask);
	surface->refs = 1;
	if (surface->backend == PT_NULL) {
		pt_free(surface);
		return PT_NULL;
	}

	return surface;
}

ptgui_surface_t *ptgui_surface_create_from_data(void *pixels,
			pt_int32_t width, pt_int32_t height, pt_int32_t depth, pt_int32_t pitch,
			pt_uint32_t Rmask, pt_uint32_t Gmask, pt_uint32_t Bmask, pt_uint32_t Amask)
{
	ptgui_surface_t *surface;

	surface = (ptgui_surface_t *)pt_malloc(sizeof(ptgui_surface_t));
	surface->backend = SDL_CreateRGBSurfaceFrom(pixels, width, height, depth, pitch, Rmask, Gmask, Bmask, Amask);
	surface->refs = 1;
	if (surface->backend == PT_NULL) {
		pt_free(surface);
		return PT_NULL;
	}

	return surface;
}

ptgui_surface_t * ptgui_surface_create_from_file(const char *src)
{
	ptgui_surface_t *surface;

	surface = (ptgui_surface_t *)pt_malloc(sizeof(ptgui_surface_t));
	surface->backend = SDL_LoadBMP_RW(SDL_RWFromFile(src, "rb"), 1);;
	surface->refs = 1;

	ptgui_surface_set_color_key(surface, SDL_SRCCOLORKEY, 0);
	if (surface->backend == PT_NULL) {
		pt_free(surface);
		return PT_NULL;
	}

	return surface;
}

pt_int32_t ptgui_surface_save_to_file(ptgui_surface_t *surface, const char *dst)
{
	return SDL_SaveBMP_RW(surface->backend, SDL_RWFromFile(dst, "w"), 1);
}

void ptgui_surface_free(ptgui_surface_t *surface)
{
	if (surface != &screen) {
		SDL_FreeSurface(surface->backend);
		if (--surface->refs > 0) {
			return;
		}
		pt_free(surface);		
	}
}

pt_int32_t ptgui_surface_lock(ptgui_surface_t *surface)
{
	return SDL_LockSurface(surface->backend);
}

void ptgui_surface_unlock(ptgui_surface_t *surface)
{
	SDL_UnlockSurface(surface->backend);
}

pt_int32_t ptgui_surface_set_color_key
			(ptgui_surface_t *surface, pt_uint32_t flag, pt_uint32_t key)
{
	return SDL_SetColorKey(surface->backend, flag, key);
}

pt_int32_t ptgui_surface_set_alpha(ptgui_surface_t *surface, pt_uint32_t flag, pt_uint8_t alpha)
{
	return SDL_SetAlpha(surface->backend, flag, alpha);
}

void ptgui_surface_set_clipping(ptgui_surface_t *surface,
				pt_int32_t top, pt_int32_t left, pt_int32_t bottom, pt_int32_t right)
{
	SDL_SetClipping(surface->backend, top, left, bottom, right);
}

pt_int32_t ptgui_surface_fill_rect
		(ptgui_surface_t *dst, ptgui_rect_t *dstrect, pt_uint32_t color)
{
	SDL_Rect rect;

	rect.x = dstrect->x1;
	rect.y = dstrect->y1;
	rect.h = ptgui_rect_height(*dstrect);
	rect.w = ptgui_rect_width(*dstrect);

	return SDL_FillRect(dst->backend, &rect, color);
}

pt_uint16_t ptgui_surface_get_width (ptgui_surface_t *surface)
{
	return ((SDL_Surface*)(surface->backend))->w;
}

pt_uint16_t ptgui_surface_get_height (ptgui_surface_t *surface)
{
	return ((SDL_Surface*)(surface->backend))->h;
}

int ptgui_surface_blit
			(ptgui_surface_t *src, ptgui_rect_t *srcrect,
			 ptgui_surface_t *dst, ptgui_rect_t *dstrect)
{
	SDL_Rect rect1, rect2;
	SDL_Rect *rect3, *rect4;

	if (srcrect == NULL) {
		rect3 = NULL;
	}
	else {
		rect1.x = srcrect->x1;
		rect1.y = srcrect->y1;
		rect1.h = ptgui_rect_height(*srcrect);
		rect1.w = ptgui_rect_width(*srcrect);
		rect3 = &rect1;
	}
	
	if (dstrect == NULL) {
		rect4 = NULL;
	}
	else {
		rect2.x = dstrect->x1;
		rect2.y = dstrect->y1;
		rect2.h = ptgui_rect_height(*dstrect);
		rect2.w = ptgui_rect_width(*dstrect);
		rect4 = &rect2;
	}

	return SDL_UpperBlit(src->backend, rect3, dst->backend, rect4);
}

void ptgui_surface_draw_pixel(ptgui_surface_t *surface,
                     pt_int16_t x, pt_int16_t y, pt_uint32_t color)
{
	if (x < ptgui_surface_get_width(surface) && y < ptgui_surface_get_height(surface)) {
		SDL_DrawPixel(surface->backend, x, y, color);
	}
}

void ptgui_surface_draw_line(ptgui_surface_t *surface,
                    pt_uint16_t x1, pt_uint16_t y1, pt_uint16_t x2, pt_uint16_t y2,
                    pt_uint32_t color)
{
	if ( x1 >= ptgui_surface_get_width(surface))  x1 = ptgui_surface_get_width(surface) - 1;
	if ( y1 >= ptgui_surface_get_height(surface))  y1 = ptgui_surface_get_height(surface) - 1;

	if ( x2 >= ptgui_surface_get_width(surface))  x2 = ptgui_surface_get_width(surface) - 1;
	if ( y2 >= ptgui_surface_get_height(surface))  y2 = ptgui_surface_get_height(surface) - 1;

	SDL_DrawLine(surface->backend, x1, y1, x2, y2, color);
}

char *ptgui_surface_get_error (void)
{
	return SDL_GetError();
}